using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;

namespace Developex.DatabaseWrapper.Fields
{
	/// <summary>
	/// Foreign key field
	/// </summary>
	/// <typeparam name="T">Foreign field type</typeparam>
	/// <typeparam name="FRow">Foreign object type</typeparam>
	public class ForeignKeyField<T, FRow> : ForeignKeyFieldBase<T, FRow> where FRow : Row, new()
	{
		#region Implementation of abstract memners

		///<summary>
		/// Get join expression for this field
		///</summary>
		///<returns></returns>
		public override string GetJoinExpression()
		{
			FRow frow = Object;
			string prefix = GetJoinPrefix();
			string joinTableName = prefix + frow.TableName;
			return string.IsNullOrEmpty(prefix) ? string.Format(@"
LEFT JOIN [{0}] ON [{1}].[{2}] = [{0}].[{3}]
", frow.TableName, Parent.JoinTableName, Name, frow.PrimaryKeyField.Name)
				  : string.Format(@"
LEFT JOIN [{0}] [{1}] ON [{2}].[{3}] = [{1}].[{4}]
", frow.TableName, joinTableName, Parent.JoinTableName, Name, frow.PrimaryKeyField.Name);
		}

		#endregion

		#region Overrides of ForeignKeyFieldBase

		///<summary>
		/// Forein Object field
		///</summary>
		public override FRow Object
		{
			get
			{
				FRow frow = base.Object;

				// auto set primary key
				if (!frow.PrimaryKeyField.IsInitialized() && IsInitialized())
				{
					object value = GetValue();
					if (value != null)
						frow.PrimaryKeyField.InitValue(value);
				}

				return frow;
			}
		}

		#endregion

		#region Overrides of Field

		/// <summary>
		/// Set value and primary key for foreign table object
		/// </summary>
		/// <param name="value"></param>
		protected override void Set(object value)
		{
			if (value != null && value != DBNull.Value)
			{
				Object.PrimaryKeyField.InitValue(value);
			}
			base.Set(value);
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="insertDefaultValue"></param>
		/// <param name="doFullLoad"></param>
		public ForeignKeyField(string name, T insertDefaultValue, FieldFlags flags, bool doFullLoad)
			: base(name, insertDefaultValue, flags, doFullLoad)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="doFullLoad"></param>
		public ForeignKeyField(string name, FieldFlags flags, bool doFullLoad)
			: base(name, flags, doFullLoad)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="doFullLoad"></param>
		public ForeignKeyField(string name, bool doFullLoad)
			: base(name, doFullLoad)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="insertDefaultValue"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="simpleNamingMode"></param>
		public ForeignKeyField(string name, T insertDefaultValue, FieldFlags flags, bool doFullLoad, bool simpleNamingMode)
			: base(name, insertDefaultValue, flags, doFullLoad, simpleNamingMode)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="simpleNamingMode"></param>
		public ForeignKeyField(string name, FieldFlags flags, bool doFullLoad, bool simpleNamingMode)
			: base(name, flags, doFullLoad, simpleNamingMode)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="simpleNamingMode"></param>
		public ForeignKeyField(string name, bool doFullLoad, bool simpleNamingMode)
			: base(name, doFullLoad, simpleNamingMode)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		public ForeignKeyField(string name)
			: base(name)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		public ForeignKeyField(string name, FieldFlags flags)
			: base(name, flags)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="insertDefaultValue"></param>
		public ForeignKeyField(string name, FieldFlags flags, T insertDefaultValue)
			: base(name, flags, insertDefaultValue)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="insertDefaultValue"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, T insertDefaultValue, FieldFlags flags, bool doFullLoad, object[] cretionParameters)
			: base(name, insertDefaultValue, flags, doFullLoad, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, FieldFlags flags, bool doFullLoad, object[] cretionParameters)
			: base(name, flags, doFullLoad, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, bool doFullLoad, object[] cretionParameters)
			: base(name, doFullLoad, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="insertDefaultValue"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="simpleNamingMode"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, T insertDefaultValue, FieldFlags flags, bool doFullLoad, bool simpleNamingMode, object[] cretionParameters)
			: base(name, insertDefaultValue, flags, doFullLoad, simpleNamingMode, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="simpleNamingMode"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, FieldFlags flags, bool doFullLoad, bool simpleNamingMode, object[] cretionParameters)
			: base(name, flags, doFullLoad, simpleNamingMode, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="doFullLoad"></param>
		/// <param name="simpleNamingMode"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, bool doFullLoad, bool simpleNamingMode, object[] cretionParameters)
			: base(name, doFullLoad, simpleNamingMode, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, object[] cretionParameters)
			: base(name, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, FieldFlags flags, object[] cretionParameters)
			: base(name, flags, cretionParameters)
		{
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="name"></param>
		/// <param name="flags"></param>
		/// <param name="insertDefaultValue"></param>
		/// <param name="cretionParameters"></param>
		public ForeignKeyField(string name, FieldFlags flags, T insertDefaultValue, object[] cretionParameters)
			: base(name, flags, insertDefaultValue, cretionParameters)
		{
		}

		#endregion

		#region ICloneable

		///<summary>
		/// Create object 
		///</summary>
		///<returns></returns>
		/// <remarks>
		/// Here should be only object creation, all data copy should be in overrided Clone function.
		/// Used only in base version of Clone function.
		/// Should be overrided for ICloneable interface.
		/// </remarks>
		protected override Field<T> CreateObjectForClone()
		{
			return new ForeignKeyField<T, FRow>(null);
		}

		#endregion
	}
}
